/***************************************************************
 *
 * (c) 2008 Markus Dittrich 
 *
 * This program is free software; you can redistribute it 
 * and/or modify it under the terms of the GNU General Public 
 * License Version 3 as published by the Free Software Foundation. 
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License Version 3 for more details.
 *
 * You should have received a copy of the GNU General Public 
 * License along with this program; if not, write to the Free 
 * Software Foundation, Inc., 59 Temple Place - Suite 330, 
 * Boston, MA 02111-1307, USA.
 *
 ****************************************************************/

#ifndef DATAOBJECT_H 
#define DATAOBJECT_H

/** boost include */
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>

/** STL includes */
#include <algorithm>
#include <vector>


/* reserved size for vector<double> to store data */
const int RESERVED_SIZE = 50000;

/* if x or y column is set to ELEMENT_COUNT it "counts"
 * the number of elements in the other column */
const int ELEMENT_COUNT = -1;
const int ELEMENTS_UNSET = -2;


/****************************************************************
 *
 * The data_object.holds a particular data set
 *
 ***************************************************************/
class DataObject : public boost::noncopyable
{

public:

  explicit DataObject(unsigned int numColumns);
  ~DataObject();

  /* append to Data_ */
  void append(const std::vector<double>& lineItems);

  /* return number of rows and columns of stored data */
  int get_num_rows() const;
  int get_num_columns() const;

  /* returns the currently active x and y columns */
  int get_active_x_column() const;
  int get_active_y_column() const;

  /* sets the new active x and y columns */
  void set_active_x_column(int newXColumn);
  void set_active_y_column(int newYColumn);

  /* getter functions returning x/y data */
  const std::vector<double>& get_x_data() const;
  const std::vector<double>& get_y_data() const;

  /* returns all data contained in a particular row */
  const std::vector<double> get_row_data(int row) const;

  
private:

  /* no copying/assignment allowed */
  DataObject(const DataObject& anObject);
  const DataObject& operator=(const DataObject& anObject);

  /* member functions */
  void setup_() const;
  void assign_columns_() const;

  /* container holding all data */
  mutable std::vector<std::vector<double> > Data_;

  /* empty dummy vector */
  std::vector<double> EmptyVector_;

  /* flag forcing calls to setup routines */
  mutable bool needInitialSetup_;

  /* number of columns present in Data_ */
  int NumColumns_;

  /* currently assigned columns and their minmax
   * they are defined mutable to keep the public
   * accessor function logically const */
  mutable int XDataColumn_;
  mutable int YDataColumn_;
};



/*****************************************************************
 *
 * define some inline member functions
 *
 *****************************************************************/

//----------------------------------------------------------------
// return number of rows of stored data
//----------------------------------------------------------------
inline int DataObject::get_num_rows() const 
{ 
  return Data_[0].size(); 
}


//----------------------------------------------------------------
// return number of columns of stored data
//----------------------------------------------------------------
inline int DataObject::get_num_columns() const 
{ 
  return NumColumns_;
}



//---------------------------------------------------------------
// sets the currently active x and y columns;
// NOTE: newXColumn == 0 corresponds to ELEMENT_COUNT and we
// hence have to substract 1
//---------------------------------------------------------------
inline void DataObject::set_active_x_column(int newXColumn)
{
  XDataColumn_ = newXColumn - 1;
}

inline void DataObject::set_active_y_column(int newYColumn)
{
  YDataColumn_ = newYColumn - 1;
}


/*****************************************************************
 *
 * convenience typedef 
 *
 *****************************************************************/
typedef boost::shared_ptr<DataObject> DataObjectPtr;


#endif
